package cn.bytest.netty.protocol;

import cn.bytest.netty.exchange.NettyExchanger;
import cn.bytest.netty.inovker.SpeedRpcInvoker;
import cn.bytets.rpc.api.exchange.ExchangeClient;
import cn.bytets.rpc.api.invoke.Invoker;
import cn.bytets.rpc.api.protocol.AbstractProtocol;
import cn.bytets.rpc.common.URL;
import cn.bytets.rpc.common.utils.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class NettyProtocol extends AbstractProtocol {

    private static final Object PRESENT = new Object();

    private final ConcurrentMap<String, Object> locks = new ConcurrentHashMap<>();
    /**
     * <host:port,Exchanger>
     */
    private final Map<String, List<ExchangeClient>> referenceClientMap = new ConcurrentHashMap<>();
    @Override
    public <T> Invoker<T> buildInvoker(Class<T> type, URL url) {
        SpeedRpcInvoker invoker = new SpeedRpcInvoker(type, url,getClients(url),invokers);
        invokers.put(invoker,PRESENT);
        return invoker;
    }

    public ExchangeClient[] getClients(URL url){
        String key = url.getAddress();
        //TODO 这里需要同URL获取是否共享链接
        List<ExchangeClient> list = getSharedClient(url, 1);
        ExchangeClient[] client = new ExchangeClient[1];
        for (int i = 0; i < client.length; i++) {
            //这里需判断是否共享
            client[i] = list.get(i);
        }
        return client;
    }
    /**
     * Bulk build client
     *
     * @param url
     * @param connectNum
     * @return
     */
    private List<ExchangeClient> buildReferenceCountExchangeClientList(URL url, int connectNum) {
        List<ExchangeClient> clients = new ArrayList<>();

        for (int i = 0; i < connectNum; i++) {
            clients.add(buildReferenceCountExchangeClient(url));
        }

        return clients;
    }
    /**
     * 这里留作扩展
     * @param url
     * @return
     */
    private ExchangeClient buildReferenceCountExchangeClient(URL url){
        return initClient(url);
    }

    private ExchangeClient initClient(URL url){
        //TODO 使用SPI方式 Exchangers 获取 ExchangeClient
        return new NettyExchanger().connect(url);
    }

    /**
     * 获取缓存中的链接客户端
     * @param url
     * @param connections
     * @return
     */
    public List<ExchangeClient> getSharedClient(URL url, int connections){
        String key = url.getAddress();
        List<ExchangeClient> clients = referenceClientMap.get(key);

        if (!CollectionUtils.isEmpty(clients)){
            //TODO 检查是否关闭
            return clients;
        }
        locks.putIfAbsent(key,new Object());
        synchronized (locks.get(key)){
            clients = referenceClientMap.get(key);
            if (!CollectionUtils.isEmpty(clients)){
                //TODO 检查是否关闭
                return clients;
            }
            connections = Math.max(connections,1);
            if (CollectionUtils.isEmpty(clients)){
                clients = buildReferenceCountExchangeClientList(url, connections);
                referenceClientMap.put(key,clients);
            } else {
                for (int i = 0; i < clients.size(); i++) {
                    ExchangeClient referenceCountExchangeClient = clients.get(i);
                    // If there is a client in the list that is no longer available, create a new one to replace him.
//                    if (referenceCountExchangeClient == null || referenceCountExchangeClient.isClosed()) {
//                        clients.set(i, buildReferenceCountExchangeClient(url));
//                        continue;
//                    }

                    //referenceCountExchangeClient.incrementAndGetCount();
                }
            }
            locks.remove(key);
        }
        return clients;
    }

}
